//window.$ = {
//	whoAmI: function() {
//		console.log('这是外部框架');
//	}
//};
// 创建最外层匿名函数
(function(window, undefined) {
	var Cat = (function() {
		//给Cat加上$ 的别名
		var Cat = function(selector, context) {
			//Cat实际上是初始化构造函数的加强模式
			//Cat其实是Cat.fn.init返回的一个对象
			//返回一个init选择的一个数组selector
			return new Cat.fn.init(selector, context);
		};
		//将别的框架定义的$暂存,用内部变量保存Cat运行之前的$和Cat的状态，在后来防冲突是还原两个变量
		//					_$ = window.$,
		//					_Cat = window.Cat;
		//将Cat的对象原型赋给了Cat.fn
		Cat.fn = Cat.prototype = {
			//构造器
			constructor: Cat,
			//返回的是一个javascript对象
			init: function(selector, context) {
				var REG_ID = /^#((?:[\w\u00c0-\uFFFF\-]|\\.)+)$/;
				var REG_CLASS = /^\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)$/;
				var REG_TAG = /^((?:[\w\u00c0-\uFFFF\-]|\\.)+)$/;
				var REG_ATTR = /^\[[A-Za-z0-9_-\S]+\]$/;
				if(REG_ID.test(selector)) {
					console.log('this is id selector');
					var parent = context || document;
					var ele = document.getElementById(selector.replace(/^#/, ''));
					this.selector = selector;
					this.length = ele.length;
					if(ele === null) {
						throw new Error("can't find the element id :" + selector);
					}
					this[0] = ele[0];
					return this;
				} else if(REG_CLASS.test(selector)) {
					console.log('this is a class selector');
					var parent = context || document;
					var ele = document.getElementsByClassName(selector.replace(/^\./, ''));
					this.selector = selector;
					this.length = ele.length;
					if(ele === null) {
						throw new Error("can't find the element class :" + selector);
					}
					for(var i = 0; i < this.length; i += 1) {
						this[i] = ele[i];
					}
					return this;
				} else if(REG_TAG.test(selector)) {
					console.log('this is a tag selector');
					var parent = context || document;
					var ele = document.getElementsByTagName(selector);
					this.selector = selector;
					this.length = ele.length;
					if(ele === null) {
						throw new Error("can't find the element tag :" + selector);
					}
					for(var i = 0; i < this.length; i += 1) {
						this[i] = ele[i];
					}
					return this;
				} else if(/\<\w+\>/.test(selector)) {
					//如果selector是一个标签元素，则生成dom节点$("<div>000</div>")
					//.test()用来判断一个字符串是否匹配某个模式,返回true或者false
					//.exec()方法用来检索字符串中正则表达式的匹配，返回一个数组
					var parentReg = /\<(\w+)\>(?:[\w\W]+)/,
						parentMatch = parentReg.exec(selector),
						parentNode = parentMatch ? parentMatch[1] : '';
					if(!parentNode) {
						//throw声明的作用是创建异常，抛出异常选择器无法被解析
						throw 'the selector can not parse a element';
					}
					//RegExp对象是正则表达式的缩写创建一个正则表达式对象
					var contentReg = new RegExp('\<' + parentNode + '\>([\\w\\W]+)\<\/' + parentNode + '\>'),
						contentMatch = contentReg.exec(selector),
						contentHTML = contentMatch ? contentMatch[1] : '';
					var parent = document.createElement(parentNode);
					parent.innerHTML = contentHTML;
					this[0] = parent;
					this.length = 1;
					return this;
				} else {
					//其他情况使用querySelectorAll
					var parent = context || document;
					//querySelectorAll一个方法获取选择器ie8以上支持
					var nodeList = parent.querySelectorAll(selector);
					this.length = nodeList.length;
					this.selector = selector;
					for(var i = 0; i < this.length; i += 1) {
						this[i] = nodeList[i];
					}
					return this;
				}
			},
			//版本号
			version: '0.1.3',
			//开始是一个空的选择器
			selector: '',
			//初始长度为0
			length: 0,
			size: function() {
				return this.length;
			},
			each: function(callback) {
				return Cat.each(this, callback);
			},
			eq: function(i) {
				i = +i;
				return i === -1 ? this.slice(i) : this.slice(i, i + 1);
			},
		};
		//将Cat的原型的方法挂载到new出来的新的Cat对象上面去
		//将Cat.fn赋值给Cat.fn.init.prototype是为了实例化
		//为了可以去调用init外面的方法，这样Cat.fn.init.prototype的原型也就是Cat的原型对象就是Cat.fn,赋值了之后在调用的时候，当init中没有方法的时候，就会去原型函数中去调用
		Cat.fn.init.prototype = Cat.fn;
		//表明Cat以及Cat的原型都指向同一个继承方法
		//合并内容到第一个参数中去，核心，之后大部分扩展使用此机制
		//通过Cat.fn.extend扩展的函数，大部分都会调用Cat.extend扩展的同名函数
		Cat.extend = Cat.fn.extend = function(destination, source) {
			//如果来源是不存在的,复制的目的地。
			if(typeof source === 'undefined') {
				source = destination;
				destination = this;
			}
			for(var property in source) {
				if(source.hasOwnProperty(property)) { //判断来源是否有特定的属性--原型
					destination[property] = source[property];
				}
			}
			return destination;
		};
		//释放命名空间

		//在Cat上扩展静态方法
		Cat.extend({
			//将noConflict释放命名空间方法挂载在jquery对象上
			noConflict: function(deep) {
				//默认处理$
				//用来判断全局变量是否等于Cat，如果等于，则还原$为Cat运行之前的变量
				if(window.$ === Cat) {
					window.$ = _$;
				}
				//如果传入一个true，开启深度冲突处理，处理Cat冲突，将全局Cat还原为之前的状况
				if(deep && window.Cat === Cat) {
					window.Cat = _Cat;
				}
				return Cat;
			},
			//用来判定对象类型：undefined，null，boolean，number，string，NaN，function，data，array，object，
			isUndefined: function(obj) {
				//void是一个函数，返回值永远是undefined
				//其实这种写法等同于return obj === undefined
				return obj === void 0;
			},
			isNull: function(obj) {
				return obj === null;
			},
			isBoolean: function(obj) {
				//toString将逻辑值转换成字符串
				//call是将a对象添加到b对象上，使b有a的所有内容，来实现b继承a
				//这样的写法是为防止toString方法被覆盖
				//使用Object.prototype上的原生toString方法判断数据类型(Object.prototype.toString.call(value);)
				//如果obj是一个true或者false，则返回[object Boolean]
				return Object.prototype.toString.call(obj) === '[object Boolean]';
			},
			isNumber: function(obj) {
				//如果obj是一个number，则返回[object Number]
				return Object.prototype.toString.call(obj) === '[object Number]';
			},
			isString: function(obj) {
				//如果obj是一个string，则返回[object String]
				return Object.prototype.toString.call(obj) === '[object String]';
			},
			isNaN: function(obj) {
				return obj !== obj;
			},
			isFunction: function(obj) {
				return Object.prototype.toString.call(obj) === '[object Function]';
			},
			isDate: function(obj) {
				return Object.prototype.toString.call(obj) === '[object Date]';
			},
			isWindow: function(obj) {
				return obj != null && obj.window == window;
			},
			isArray: function(obj) {
				return Object.prototype.toString.call(obj) === '[object Array]';
			},
			isObject: function(obj) {
				//如果obj是一个对象，则返回[object Object]
				return Object.prototype.toString.call(obj) === '[object Object]';
			},
			has: function(obj, key) {
				//hasOwnProperty判断一个属性是定义在对象本身而不是继承自原型链,同时下列写法是引用外部的hasOwnPrototype来判断属性，为了防止hasOwnPrototype方法被覆盖的兼容写法
				return Object.prototype.hasOwnProperty.call(obj, key);
			},

			//判断数组,字符串,obj是否为空 
			isEmpty: function(obj) {
				if(obj == null) return true;
				if($.isArray(obj) || $.isString(obj)) return obj.length === 0;
				for(var key in obj)
					if($.has(obj, key)) return false;
				return true;
			},
			each: function(object, callback) {
				var i = 0,
					length = object.length;
				for(; i < length; i++) {
					callback.call(object[i], i, object[i]);
				}
				return this;
			},
			//将选择器获取的nodeList伪数组对象转化为真正的数组对象
			makeArray: function(obj) {
				var ret = [];
				var len = obj.length;
				if(len == null || typeof obj === 'string' || $.isFunction(obj) || $.isWindow(obj)) {;
					ret[0] = obj;
				} else {
					while(len) {
						ret[--len] = obj[len];
					}
				}
				return ret;
			}
		});
		//Cat对象构造完毕，之后的都是对Cat以及Cat对象扩展
		console.log(Cat);
		return Cat;
	})();
	//之后的扩展
	//文档处理操作
	Cat.fn.extend({
		append: function(child) {
			if(Cat.isString(child)) {
				//bug(选择器对于生成标签不能添加类名属性)
				child = Cat(child)[0];
			}
			this.each(function(index, element) {
				element.appendChild(child);
			});

			child = null;
			return this;
		},
		prepend: function(child) {
			if($.isString(child)) {
				child = $(child)[0];
			}
			this.each(function(index, element) {
				//insertBefore()在指定的已有子节点之前插入新的子节点
				element.insertBefore(child, element.childNodes[0]);
			});
			child = null;
			return this;
		},
		remove: function() {
			this.each(function(index, element) {
				element.parentNode.removeChild(v);
			});
			return this;
		},
		empty: function() {
			this.each(function(index, element) {
				element.innerHTML = '';
			});
			return this;
		},
	});
	//文档元素过滤操作
	Cat.fn.extend({
		children: function(selector) {
			return $(selector, this[0]);
		},
		parent: function() {
			return $(this[0].parentElement);
		},
		siblings: function() {
			var n = (this[0].parentElement || {}).firstChild,
				elem = this[0]
			matched = [];
			for(; n; n = n.nextSibling) {
				if(n.nodeType === 1 && n !== elem) {
					matched.push(n);
				}
			}
			return $(matched);
		}
	});
	//样式操作
	Cat.fn.extend({
		css: function(cssRules, value) {

			//cssName need to Converted into camel casing。
			//className需要转化为驼峰写法
			var transformHump = function(name) {
				return name.replace(/\-(\w)/g, function(all, letter) {
					//toUpperCase()用于把字符串转换为大写
					return letter.toUpperCase();
				});
			};

			if(Cat.isString(cssRules)) {
				if(Cat.isUndefined(value)) {
					//Document.defaultView在浏览器中，该属性返回当前 document 对象所关联的 window 对象，如果没有，会返回 null
					//getComputedStyle是一个可以获取当前元素所有最终使用的CSS属性值
					//getPropertyValue方法可以获取CSS样式申明对象上的属性值
					return document.defaultView.getComputedStyle(this[0], null)
						.getPropertyValue(cssRules);
				} else {
					this.each(function(index, element) {
						element.style[transformHump(cssRules)] = value;
					});
				}
			} else {
				for(var attr in cssRules) {
					//由于我修改了jqfree的代码，此处的each方法需要重新写
					//console.log(this);//this是init选择对象,attr是background，cssRules[attr]是值
					console.log(this);
					this.each(function(index, element) {
						//bug，大大的bug，由于我的选择器返回的不是一个数组，导致仿照jquery的each方法在this是对象时有bug，底下做一下兼容
						//if(/^[0-9]*$/.test(index)) {
						//	newindex = index;
						//} else {
						//	return;
						//}
						//console.log(element);
						//此处是属性的两种表现形式
						this.style[transformHump(attr)] = cssRules[attr];
					});
				}
			}
			return this;
		},
	});
	//属性操作
	Cat.fn.extend({
		attr: function(attrName, attrValue) {
			if(!$.isUndefined(attrValue)) {
				if(attrName === 'value' || attrName === 'href') {
					this.each(function(index, element) {
						element[attrName] = attrValue;
					});
				} else {
					this.each(function(index, element) {
						element.setAttribute(attrName, attrValue);
					});
				}
			}
			return attrName === 'value' || attrName === 'href' ? this[0][attrName] : this[0].getAttribute(attrName);
		},
		removeAttr: function(attrName) {
			this.each(function(index, element) {
				element.removeAttribute(attrName);
			});
			return this;
		},
		hasClass: function(className) {
			//classList are strong，but IE9 does not support。
			return this[0].classList.contains(className);;
		},
		addClass: function(className) {
			this.each(function(index, element) {
				//please use 'v.className += className' if you need support IE9.
				element.classList.add(className);
			});
			return this;
		},
		removeClass: function(className) {
			this.each(function(index, element) {
				element.classList.remove(className);
			});
			return this;
		},
		data: function(dataName, dataValue) {
			if(typeof dataValue !== 'undefined') {
				this.each(function(index, element) {
					//HTML5，dataset，IE10 does not support。
					element.dataset[dataName] = dataValue;
				});
				return this;
			} else {
				//try to parse result to JSON
				try {
					return JSON.parse(this[0].dataset[dataName]);
				} catch(e) {
					return this[0].dataset[dataName]
				}
			}
		},
		html: function(htmlText) {
			if($.isUndefined(htmlText)) {
				return this[0].innerHTML;
			} else {
				this.each(function(index, element) {
					element.innerHTML = htmlText;
				});
			}
		},
		val: function(newValue) {
			console.log(this.selector);
			//start val function body
			//简单地判断传入值非法, 最好使用正则
			if(!(this.selector && this.selector.indexOf('#') == 0 && this.selector.length != 1)) return;
			var id = this.selector.substring(1);
			var obj = document.getElementById(id);
			//如果对象存在
			if(obj) {
				if(newValue == undefined)
					//获取目标对象的值
					return obj.value;
				//将目标对象的value属性设置为newValue
				obj.value = newValue;
				//为了使方法可以连续调用, 返回当前实例
				return this;
			}
		},
	});
	//event事件函数
	Cat.fn.extend({
		on: function(event, func) {
			this.each(function(index, element) {
				//dom level 2，IE8 not support。
				element.addEventListener(event, func, false);
			});
			return this;
		},
		off: function(event, func) {
			this.each(function(index, element) {
				element.removeEventListener(event, func, false);
			});
			return this;
		},
		trigger: function(type, data) {
			var event = document.createEvent('HTMLEvents');
			event.initEvent(type, true, true);
			event.data = data || {};
			event.eventName = type;
			event.target = this;
			this.each(function(v, k) {
				v.dispatchEvent(event);
			});
			return this;
		},
	});
	//effect
	Cat.fn.extend({
		hide: function() {
			this.each(function() {
				this.style.display = 'none';
			});
			return this;
		},
		show: function() {
			this.each(function() {
				this.style.display = 'block';
			});
			return this;
		},
	});
	//ajax
	Cat.extend({
		//opts是一个类json的键对值
		ajax: function(opts) {
			var xhr = new XMLHttpRequest(),
				type = opts.type || 'GET',
				url = opts.url,
				success = opts.success,
				error = opts.error,
				params;
			params = (function(obj) {
				var str = '';
				for(var prop in obj) {
					str += prop + '=' + obj[prop] + '&'
				}
				str = str.slice(0, str.length - 1);
				return str;
			})(opts.data);
			//转化成大写
			type = type.toUpperCase();
			if(type === 'GET') {
				url += url.indexOf('?') === -1 ? '?' + params : '&' + params;
			}
			xhr.open(type, url);
			if(type === 'POST') {
				xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			}
			xhr.send(params ? params : null);
			//return promise
			return new Promise(function(resolve, reject) {
				//onload在异步请求之后执行，
				//please use 'onreadystatechange' if need support IE9-
				xhr.onload = function() {
					if(xhr.status === 200) {
						resolve(xhr.response);
					} else {
						reject(xhr.response);
					}
				};
			});
		},
		jsonp: function(opts) {
			//to produce random string
			var generateRandomAlphaNum = function(len) {
				var rdmString = '';
				for(; rdmString.length < len; rdmString += Math.random().toString(36).substr(2));
				return rdmString.substr(0, len);
			}
			var url = opts.url,
				callbackName = opts.callbackName || 'jsonpCallback' + generateRandomAlphaNum(10),
				callbackFn = opts.callbackFn || function() {};
			if(url.indexOf('callback') === -1) {
				url += url.indexOf('?') === -1 ? '?callback=' + callbackName : '&callback=' + callbackName;
			}
			var eleScript = document.createElement('script');
			eleScript.type = 'text/javascript';
			eleScript.id = 'jsonp';
			eleScript.src = url;
			document.getElementsByTagName('HEAD')[0].appendChild(eleScript);
			// window[callbackName] = callbackFn;
			//return promise
			return new Promise(function(resolve, reject) {
				window[callbackName] = function(json) {
					resolve(json);
				}
				//onload are executed just after the sync request is comple，
				//please use 'onreadystatechange' if need support IE9-
				eleScript.onload = function() {
					//delete the script element when a request done。
					document.getElementById('jsonp').outerHTML = '';
					eleScript = null;
				};
				eleScript.onerror = function() {
					document.getElementById('jsonp').outerHTML = '';
					eleScript = null;
					reject('error');
				}
			});
		}
	});
	//cookie
	Cat.extend({
		cookie: function(cookieName, cookieValue, day) {
			var readCookie = function(name) {
				var arr,
					reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'),
					matched = document.cookie.match(reg);
				if(arr = matched) {
					return unescape(arr[2]);
				} else {
					return null;
				}
			};
			var setCookie = function(name, value, time) {
				var Days = time || 30;
				var exp = new Date();
				exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000);
				document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString();
			};
			if(cookieName && cookieValue) {
				//set cookie
				setCookie(cookieName, cookieValue, day);
			} else if(cookieName && $.isNull(cookieValue)) {
				//delete cookie
				setCookie(cookieName, '', -1);
			} else if(cookieName) {
				//read cookie
				return readCookie(cookieName);
			}
		}
	});
	//其他额外功能
	Cat.extend({
		//$.parseTime(new Date().getTime(), 'YYYY-MM-DD hh:mm:ss')
		//result: "2016-08-03 16:14:12"
		parseTime: function(timeStamp, format) {
			var date = new Date(timeStamp);
			var o = {
				'M+': date.getMonth() + 1, //month 
				'D+': date.getDate(), //day 
				'h+': date.getHours(), //hour 
				'm+': date.getMinutes(), //minute 
				's+': date.getSeconds(), //second 
				'S': date.getMilliseconds() //millisecond 
			}
			if(/(Y+)/.test(format)) {
				format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
			}
			for(var k in o) {
				if(new RegExp('(' + k + ')').test(format)) {
					format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length));
				}
			}
			return format;
		},
		//$.parseUrl(location.href)
		//return an object contains the folling info.
		parseUrl: function(url) {
			var a = document.createElement('a');
			a.href = url;
			return {
				source: url,
				protocol: a.protocol.replace(':', ''),
				host: a.hostname,
				port: a.port,
				query: a.search,
				params: (function() {
					var ret = {},
						seg = a.search.replace(/^\?/, '').split('&'),
						len = seg.length,
						i = 0,
						s;
					for(; i < len; i++) {
						if(!seg[i]) {
							continue;
						}
						s = seg[i].split('=');
						ret[s[0]] = s[1];
					}
					return ret;
				})(),
				file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1],
				hash: a.hash.replace('#', ''),
				path: a.pathname.replace(/^([^\/])/, '/$1'),
				relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [, ''])[1],
				segments: a.pathname.replace(/^\//, '').split('/')
			};
		},
		//$.toFixedFloat(15.658, 2)
		//result: 15.66
		toFixedFloat: function(value, precision) {
			var power = Math.pow(10, precision || 0);
			return String(Math.round(value * power) / power);
		},
		//for generate random string
		//$.generateRandomAlphaNum(5)
		//random result: like "rc3sr".
		generateRandomAlphaNum: function(len) {
			var rdmString = '';
			for(; rdmString.length < len; rdmString += Math.random().toString(36).substr(2));
			return rdmString.substr(0, len);
		}
	});
	// Expose jQuery to the global object
	//将此前定义的jquery导出到window对象，将$.jquery挂载到window上，使我们可以在任何地方调用$.jquery对象window.$ = $,window.jQuery = jQuery
	//Cat只是一个局部变量，作用域外想要访问到就要将其挂载到window下，对外暴露接口
	window.Cat = window.$ = Cat;
	return Cat;
})(window);
////扩展新的方法.
//(function($) {
//	//alert(obj.fn);
//	$.noConflict = function() {
//		window.$ = window._$; //把$还给在开始处取得的引用.
//	};
//})(Cat);